
#include "modules/broadcast.h"
#include "core/message.h"

#define SUMMON_COUNT 3 // 召唤次数

namespace mod {
	BreadcastModule::BreadcastModule(std::shared_ptr<Context> ctx, const string &module_name) : Module(ctx, module_name), sockfd(-1) {};
	BreadcastModule::~BreadcastModule() = default;

	bool BreadcastModule::Init() { return true; }

	void BreadcastModule::Start() {
		// 创建套接字
		this->sockfd = create_udp_socket(this->ctx->config.Multicast.Port);
		if (sockfd < 0) {
			throw std::runtime_error("listener socket create failed.");
		}

		// 设置TTL
		unsigned char ttl = 1;
		if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &ttl, sizeof(ttl)) < 0) {
			throw std::runtime_error("set ttl error: " + std::to_string(errno));
		}

		// 加入组播
		struct ip_mreq group;
		group.imr_multiaddr.s_addr = inet_addr(ctx->config.Multicast.Addr.c_str());
		group.imr_interface.s_addr = INADDR_ANY;
		if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &group, sizeof(group)) < 0) {
			close(sockfd);
			throw std::runtime_error("listener setsockopt-group failed.");
		}

		// 添加监听器
		unique_ptr<Listener> listener = unique_ptr<Listener>(new Listener(sockfd, ctx->config.Multicast.Port, "MultiCast"));
		listener->handler             = summon_receiver();
		ctx->addListener(move(listener));

		// 发送召唤
		summon_sender();
	}

	void BreadcastModule::summon_sender() {
		// 组播目标地址
		struct sockaddr_in groupAddr = create_addr(this->ctx->config.Multicast.Port, ctx->config.Multicast.Addr.c_str());

		// 构建消息, Flag:: 0-PSH; 1-ACK; 2-REP;3-FIN
		biz::Message msg  = {.magic = biz::Msg_Type::SGW_SUMMON, .flag = 0};
		SummonInfo   info = {netutil::CURRENT_IP4, ctx->config.Gateway.GatewayPort, netutil::CURRENT_IP4, ctx->config.Gateway.DynamicAgentPort};

		// 如：172.16.1.130|5002|172.16.1.130|5003
		string      infoStr = info.encode();
		const char *data    = infoStr.c_str();
		msg.payload_len     = strlen(data) + 1; // 数据长度
		msg.payload_data    = (char *) malloc(msg.payload_len);
		if (msg.payload_data == NULL) {
			throw std::runtime_error("malloc error: " + std::to_string(errno));
		}
		memcpy(msg.payload_data, data, msg.payload_len);
		msg.payload_data[msg.payload_len] = '\n';

		// 临时内存对象
		size_t msg_size = message_size(msg); // 消息长度
		char  *buffer   = (char *) malloc(msg_size);
		serialize(&msg, buffer, msg_size);

		// 发送N次召唤
		uint8_t count = 0;
		while (count < SUMMON_COUNT) {
			std::this_thread::sleep_for(std::chrono::milliseconds(this->ctx->config.Multicast.Interval));
			ssize_t sentBytes = sendto(sockfd, buffer, msg_size, 0, (SOCKADDR *) &groupAddr, sizeof(groupAddr));
			if (sentBytes < 0) {
				log_error("[Broadcast] Sent[FD:%d] error: %d", sockfd, errno);
				count++;
				continue;
			}
			log_info("[Broadcast] Summon[PSH] payload { %s } @%d ...", msg.payload_data, count + 1);
			count++;
		}
		free(buffer);
		// free_message(&msg);
		// close(sockfd); 请勿关闭
	}

	listen_handler BreadcastModule::summon_receiver() {
		return [this](int fd, const char *data, ssize_t len, const char *sender_ip, const ushort sender_port) {
			(void) fd;
			if (strcmp(sender_ip, netutil::CURRENT_IP4.c_str()) != 0) {
				biz::Message msg;
				deserialize(&msg, (char *) data, (size_t) len);
				if (msg.flag == 0) { // 0:召唤，1:回应
					// 1. 召唤确认
					{
						auto si = SummonInfo::decode(string(msg.payload_data, msg.payload_len));
						log_info("[Broadcast] Summon[ACK] from %s:%d payload { %.*s } ...", sender_ip, sender_port, msg.payload_len, msg.payload_data);
						ctx->SetGatewayTable(si.GateWayIP + ":" + to_string(si.GatewayPort));
					}

					// 2. 召唤回应(收到对方的召唤后，把自己的网关信息回应给对方) Flag:: 0-PSH; 1-ACK; 2-REP;3-FIN
					{
						biz::Message reply   = {.magic = biz::Msg_Type::SGW_SUMMON, .flag = 1};
						SummonInfo   info    = {netutil::CURRENT_IP4, ctx->config.Gateway.GatewayPort, netutil::CURRENT_IP4, ctx->config.Gateway.DynamicAgentPort};
						string       infoStr = info.encode(); // 如：172.16.1.130|5002|172.16.1.130|5003
						const char  *data    = infoStr.c_str();
						reply.payload_len    = strlen(data) + 1;
						reply.payload_data   = (char *) malloc(reply.payload_len);
						if (reply.payload_data == NULL) {
							log_fatal("[Message] Malloc error: %d", errno);
							free_message(&reply);
							goto HANDLER_DONE;
						}
						memcpy(reply.payload_data, data, reply.payload_len);
						reply.payload_data[reply.payload_len] = '\n';

						// 临时内存对象
						size_t msg_size = message_size(reply);
						char  *buffer   = (char *) malloc(msg_size);
						serialize(&reply, buffer, msg_size);

						// 创建目标/客户端Socket
						struct sockaddr_in senderAddr = create_addr(sender_port, sender_ip);
						ssize_t            sentBytes  = sendto(sockfd, buffer, msg_size, 0, (SOCKADDR *) &senderAddr, sizeof(senderAddr));
						if (sentBytes < 0) {
							log_error("[Broadcast] Sent[FD:%d] error: %d", sockfd, errno);
							free(buffer);
							free_message(&reply);
							goto HANDLER_DONE;
						}
						log_info("[Broadcast] Summon[REP] target %s:%d payload { %s } ...", sender_ip, sender_port, reply.payload_data);

						free(buffer);
						free_message(&reply);
					}
				} else if (msg.flag == 1) { // REP
					// 处理召唤回应
					auto si = SummonInfo::decode(string(msg.payload_data, msg.payload_len));
					log_info("[Broadcast] Summon[FIN] from %s:%d payload { %.*s } ...", sender_ip, sender_port, msg.payload_len, msg.payload_data);
					ctx->SetGatewayTable(si.GateWayIP + ":" + to_string(si.GatewayPort));
				}

			HANDLER_DONE:
				free_message(&msg);
				// free(buffer);
			}
		};
	}

	void BreadcastModule::Stop() {
		ctx->removeByFd(sockfd);
		// close(sockfd); //???
	}
} // namespace mod
